﻿using System;

namespace MathService.DSP.Fourier
{
    /// <summary>Класс преобразования Фурье</summary>
    public static class FT
    {
        /* -------------------------------------------------------------------------------------------- */


        public static Complex W(int N)  {                              return Complex.Exp(-2 * Math.PI / N);  }

        public static Complex W(int k, int N)  {                                      return Complex.Exp(-2 * Math.PI * k / N);   }

        /* -------------------------------------------------------------------------------------------- */

        /// <summary>Прямое преобразование отсчётов функции в спектр</summary>
        /// <param name="Values">Массив отсчётов функции</param>
        /// <param name="IsInverse">Обратное преобразование</param>
        public static Complex[] FurierTransform(this double[] Values, bool IsInverse = false)
        {
            var N = Values.Length;
            var lv_Spectrum = new Complex[N];
            var w = exp.GetCoefficients(N, IsInverse);

            for(var m = 0; m < N; m++)
            {
                var P = 0.0;
                var Q = 0.0;
                for(var n = 0; n < N; n++)
                {
                    var v = Values[n];
                    var i = (m * n) % N;
                    var ww = w[i];
                    P += v * ww.cos;
                    Q += v * ww.sin;
                }
                lv_Spectrum[m] = new Complex(P / N, Q / N);
            }
            return lv_Spectrum;
        }

        /// <summary>Прямое преобразование отсчётов функции в спектр</summary>
        /// <param name="Values">Массив отсчётов функции</param>
        /// <param name="Inverse">Обратное преобразование</param>
        public static Complex[] FurierTransform(this Complex[] Values, bool Inverse = false)
        {
            var lv_Spectrum = new Complex[Values.Length];
            var N = lv_Spectrum.Length;
            var w = exp.GetCoefficients(N, Inverse);

            for(var m = 0; m < N; m++)
            {
                var P = 0.0;
                var Q = 0.0;
                for(var n = 0; n < N; n++)
                {
                    var v = Values[n];
                    var re = v.Re;
                    var im = v.Im;
                    var i = n * m % N;
                    var ww = w[i];
                    P += re * ww.cos - im * ww.sin;
                    Q += im * ww.cos + re * ww.sin;
                }
                lv_Spectrum[m] = Inverse ? new Complex(P, Q) : new Complex(P / N, Q / N);
            }
            return lv_Spectrum;
        }
    }
}
